package dao

import (
	"advertising/internal/dal"
	"advertising/internal/define"
	"advertising/internal/models"
	"context"
	"strings"
	"time"

	"192.168.1.75/go-pkg/helper"
	"gorm.io/gen/field"
	"gorm.io/gorm"

	"advertising/internal/app/grpc/client"
	"advertising/internal/app/grpc/protoc/mini_app"
)

type PublishSchedule struct{}

func (PublishSchedule) Create(ctx context.Context, db *gorm.DB, name string, position int8, startTime, endTime, duration int64, details, districtID, locationID string, publishType int8, merchantID, merchantName, createUser, createUserName string, deviceCount int64, detailsShow int8, gender, age, tag string, publishCount int64, supportActivityID string) (ID string, err error) {
	m := dal.Use(db).PublishSchedule
	var d models.PublishSchedule
	d.ID, _ = helper.UUID{}.String()
	d.Name = strings.TrimSpace(name)
	d.Position = position
	d.StartTime = startTime
	d.EndTime = endTime
	d.Duration = duration
	d.Details = details
	d.Status = 1
	d.DistrictID = districtID
	d.LocationID = locationID
	d.PublishType = publishType
	d.MerchantID = merchantID
	d.MerchantName = merchantName
	d.CreateUser = createUser
	d.CreateUserName = createUserName
	d.DeviceCount = deviceCount
	d.DetailsShow = detailsShow
	d.Gender = gender
	d.Age = age
	d.Tag = tag
	d.PublishCount = publishCount
	d.SupportActivityID = supportActivityID
	d.CreatedAt = time.Now().Unix()
	m.WithContext(ctx).Create(&d)
	return d.ID, nil
}

// 编辑
func (PublishSchedule) Update(ctx context.Context, db *gorm.DB, ID, merchantID, name string, position int8,
	startTime, endTime, duration int64, details, districtID, locationID string, deviceCount int64, detailsShow int8,
	gender, age, tag string, status int8, supportActivityID string) (err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx)
	tx.Where(m.ID.Eq(ID)).
		Where(m.MerchantID.Eq(merchantID)).
		Where(m.DeletedAt.Eq(0)).
		UpdateSimple(
			m.Name.Value(name),
			m.Position.Value(position),
			m.StartTime.Value(startTime),
			m.EndTime.Value(endTime),
			m.Duration.Value(duration),
			m.Details.Value(details),
			m.DistrictID.Value(districtID),
			m.LocationID.Value(locationID),
			m.DeviceCount.Value(deviceCount),
			m.DetailsShow.Value(detailsShow),
			m.Gender.Value(gender),
			m.Age.Value(age),
			m.Tag.Value(tag),
			m.SupportActivityID.Value(supportActivityID),
		)
	if status != 0 {
		tx.Update(m.Status, status)
	}
	return
}

// 按状态统计投放计划
func (PublishSchedule) StatusCount(ctx context.Context, db *gorm.DB, merchantID string, status int8) (count int64, err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if merchantID != "" {
		tx = tx.Where(m.MerchantID.Eq(merchantID))
	}
	if status != 0 {
		tx = tx.Where(m.Status.Eq(status))
	}
	count, _ = tx.Count()
	return
}

type ScheduleIDNameList struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

// 获取计划名称列表
func (PublishSchedule) GetScheduleNameList(ctx context.Context, db *gorm.DB, id string) (res []ScheduleIDNameList, err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if id != "" {
		if strings.Contains(id, ",") {
			tx = tx.Where(m.ID.In(strings.Split(id, ",")...))
		} else {
			tx = tx.Where(m.ID.Eq(id))
		}
	}

	tx.Order(m.ID.Desc()).Select(m.ID, m.Name).Scan(&res)
	return res, nil
}

func (PublishSchedule) List(ctx context.Context, db *gorm.DB, merchantID, ScheduleID, name, createUserName string, position, status int8, startTime, endTime int64, page, limit int, platform int, amount_thresh float32, custom_name, phone_number, out_trade_no, supportActivityID string, createdStartTime, createdEndTime int64) (res []*models.PublishSchedule, count int64, err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if merchantID != "" && merchantID != "1" {
		tx = tx.Where(m.MerchantID.Eq(merchantID))
	}
	if ScheduleID != "" {
		if strings.Contains(ScheduleID, ",") {
			tx = tx.Where(m.ID.In(strings.Split(ScheduleID, ",")...))
		} else {
			tx = tx.Where(m.ID.Eq(ScheduleID))
		}
	}
	if name != "" {
		tx = tx.Where(m.Name.Like("%" + name + "%"))
	}
	if createUserName != "" {
		tx.Where(m.CreateUserName.Like("%" + createUserName + "%"))
	}
	if position != 0 {
		tx = tx.Where(m.Position.Eq(position))
	}
	if status != 0 {
		tx = tx.Where(m.Status.Eq(status))
	}
	if startTime != 0 && endTime != 0 {
		tx = tx.Where(
			m.WithContext(ctx).
				Where(
					m.WithContext(ctx).Where(m.StartTime.Lte(startTime)).Where(m.EndTime.Gte(startTime)),
				).
				Or(
					m.WithContext(ctx).Where(m.StartTime.Gte(startTime)).Where(m.EndTime.Lte(endTime)),
				).
				Or(
					m.WithContext(ctx).Where(m.StartTime.Lte(endTime)).Where(m.EndTime.Gte(endTime)),
				),
		)
	}
	if platform == 0 { //全部

	} else if platform == 1 { //管理平台

		tx1 := tx.Where(m.OrderID.Eq("")).Or(m.OrderID.IsNull())
		tx = tx.Where(tx1)
	} else if platform == 2 { //小程序
		tx1 := tx.Where(m.OrderID.IsNotNull()).Where(m.OrderID.Neq(""))
		tx = tx.Where(tx1)
	}

	if amount_thresh > 0 {
		tx = tx.Where(m.PayAmount.Gte(amount_thresh))
	}

	if custom_name != "" {
		tx = tx.Where(m.CustomName.Like("%" + custom_name + "%"))
	}
	if phone_number != "" {
		tx = tx.Where(m.PhoneNumber.Like("%" + phone_number + "%"))
	}
	if out_trade_no != "" {
		tx = tx.Where(m.OutTradeNo.Eq(out_trade_no))
	}
	if supportActivityID != "" {
		tx = tx.Where(m.SupportActivityID.Eq(supportActivityID))
	}

	if createdStartTime != 0 && createdEndTime != 0 {
		tx = tx.Where(m.CreatedAt.Gte(createdStartTime)).Where(m.CreatedAt.Lte(createdEndTime))
	}
	//1未提审 > 5审核失败 > 2审核中 > 4待开始 > 3投放中 > 6已结束
	res, count, err = tx.Order(
		field.NewString(m.TableName(), m.Status.ColumnName().String()).FindInSet("1,5,2,4,3,6"),
		m.ID.Desc(),
	).FindByPage(Offset(page, limit))
	return
}

type ScheduleTotal struct {
	Total             int64 `json:"total"`
	UnAuditedTotal    int64 `json:"un_audited_total"`
	AuditFailTotal    int64 `json:"audit_fail_total"`
	AuditingTotal     int64 `json:"auditing_total"`
	ToStartTotal      int64 `json:"to_start_total"`
	OnPublishingTotal int64 `json:"on_publishing_total"`
	PublishEndTotal   int64 `json:"publish_end_total"`
}

func (PublishSchedule) Total(ctx context.Context, db *gorm.DB, merchantID, ScheduleID, name, createUserName string, position int8, startTime, endTime int64, supportActivityID string, createdStartTime, createdEndTime int64) (res ScheduleTotal, err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if merchantID != "" && merchantID != "1" {
		tx = tx.Where(m.MerchantID.Eq(merchantID))
	}
	if ScheduleID != "" {
		if strings.Contains(ScheduleID, ",") {
			tx = tx.Where(m.ID.In(strings.Split(ScheduleID, ",")...))
		} else {
			tx = tx.Where(m.ID.Eq(ScheduleID))
		}
	}
	if name != "" {
		tx = tx.Where(m.Name.Like("%" + name + "%"))
	}
	if createUserName != "" {
		tx.Where(m.CreateUserName.Like("%" + createUserName + "%"))
	}
	if position != 0 {
		tx = tx.Where(m.Position.Eq(position))
	}
	if supportActivityID != "" {
		tx = tx.Where(m.SupportActivityID.Eq(supportActivityID))
	}
	if createdStartTime != 0 && createdEndTime != 0 {
		tx = tx.Where(m.CreatedAt.Gte(createdStartTime)).Where(m.CreatedAt.Lte(createdEndTime))
	}
	if startTime != 0 && endTime != 0 {
		tx = tx.Where(
			m.WithContext(ctx).
				Where(
					m.WithContext(ctx).Where(m.StartTime.Lte(startTime)).Where(m.EndTime.Gte(startTime)),
				).
				Or(
					m.WithContext(ctx).Where(m.StartTime.Gte(startTime)).Where(m.EndTime.Lte(endTime)),
				).
				Or(
					m.WithContext(ctx).Where(m.StartTime.Lte(endTime)).Where(m.EndTime.Gte(endTime)),
				),
		)
	}
	res.Total, _ = tx.Count()
	res.UnAuditedTotal, _ = tx.WithContext(ctx).Where(m.Status.Eq(define.UN_AUDITED)).Count()       // 1未提审
	res.AuditFailTotal, _ = tx.WithContext(ctx).Where(m.Status.Eq(define.AUDIT_FAIL)).Count()       // 5审核失败
	res.AuditingTotal, _ = tx.WithContext(ctx).Where(m.Status.Eq(define.AUDITING)).Count()          // 2审核中
	res.ToStartTotal, _ = tx.WithContext(ctx).Where(m.Status.Eq(define.TO_START)).Count()           // 4待开始
	res.OnPublishingTotal, _ = tx.WithContext(ctx).Where(m.Status.Eq(define.ON_PUBLISHING)).Count() // 3投放中
	res.PublishEndTotal, _ = tx.WithContext(ctx).Where(m.Status.Eq(define.PUBLISH_END)).Count()     // 6已结束
	return
}

// 获取投放计划详情
func (PublishSchedule) Info(ctx context.Context, db *gorm.DB, merchantID, ID string) (data *models.PublishSchedule, count int64, err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if merchantID != "" {
		tx = tx.Where(m.MerchantID.Eq(merchantID))
	}
	if ID != "" {
		tx = tx.Where(m.ID.Eq(ID))
	}
	data, err = tx.Take()
	count, _ = tx.Count()
	return
}

// 编辑投放计划状态
func (PublishSchedule) ChangeSatatus(ctx context.Context, db *gorm.DB, merchantID, ID string, currentStatus []int8, status int8) (err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if merchantID != "" {
		tx = tx.Where(m.MerchantID.Eq(merchantID))
	}
	if ID != "" {
		tx = tx.Where(m.ID.Eq(ID))
	}
	if len(currentStatus) > 0 {
		tx = tx.Where(m.Status.In(currentStatus...))
	}
	tx.Update(m.Status, status)

	client, err := client.GetMiniAppClient()
	if err != nil {
		return
	}
	var params mini_app.SetScheduleInfoReq

	params.OrderId = ""
	params.Status = int32(status)
	_, err1 := client.SetScheduleInfo(ctx, &params)
	if err1 != nil {
		err = err1
	}
	return nil
}

func (PublishSchedule) SetOrderID(ctx context.Context, db *gorm.DB, ID string, orderID string, payAmount, paidAmount, discountAmount float32, customName, phoneNumber, outTradeNo string) (err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0))
	if ID != "" {
		tx = tx.Where(m.ID.Eq(ID))
	}
	tx.Update(m.OrderID, orderID)
	tx.Update(m.PayAmount, payAmount)
	tx.Update(m.PaidAmount, paidAmount)
	tx.Update(m.DiscountAmount, discountAmount)
	tx.Update(m.CustomName, customName)
	tx.Update(m.PhoneNumber, phoneNumber)
	tx.Update(m.OutTradeNo, outTradeNo)
	return nil
}

// 投放计划日历
func (PublishSchedule) ScheduleCalendar(ctx context.Context, db *gorm.DB, merchantID string, startTime, endTime int64) (res []*models.PublishSchedule, count int64, err error) {
	m := dal.Use(db).PublishSchedule
	tx := m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0)).
		Where(m.MerchantID.Eq(merchantID)).
		Where(
			m.WithContext(ctx).
				Where(
					m.WithContext(ctx).Where(m.StartTime.Lte(startTime)).Where(m.EndTime.Gte(startTime)),
				).
				Or(
					m.WithContext(ctx).Where(m.StartTime.Gte(startTime)).Where(m.EndTime.Lte(endTime)),
				).
				Or(
					m.WithContext(ctx).Where(m.StartTime.Lte(endTime)).Where(m.EndTime.Gte(endTime)),
				),
		)
	res, _ = tx.Find()
	count, _ = tx.Count()
	return
}

// 编辑投放计划已使用次数
func (PublishSchedule) ChangePublishUsedCount(ctx context.Context, db *gorm.DB, ID string, publishUsedCount int) (err error) {
	if ID == "" {
		return
	}

	m := dal.Use(db).PublishSchedule
	m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0)).
		Where(m.ID.Eq(ID)).
		Update(m.PublishUsedCount, publishUsedCount)
	return nil
}

// 投放中实际已经过期的投放计划
func (PublishSchedule) ExpiredSchedule(ctx context.Context, db *gorm.DB) (IDs []string, err error) {
	m := dal.Use(db).PublishSchedule
	m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0)).
		Where(m.Status.Eq(3)). // 投放中
		Where(m.EndTime.Lte(time.Now().Unix())).
		Pluck(m.ID, &IDs)
	return
}

// 投放时间已到的待投放计划更新为投放中
func (PublishSchedule) TimeToPublishSchedule(ctx context.Context, db *gorm.DB) (IDs []string, err error) {
	m := dal.Use(db).PublishSchedule
	m.WithContext(ctx).
		Where(m.DeletedAt.Eq(0)).
		Where(m.StartTime.Lte(time.Now().Unix()), m.EndTime.Gte(time.Now().Unix())).
		Where(m.Status.Eq(4)).
		Pluck(m.ID, &IDs)
	return
}
